package com.qf.listener;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.xml.ws.spi.http.HttpHandler;
import java.net.URLEncoder;
import java.util.Map;

/**
 * author:z
 * time:2021/12/30 17:06
 * description:
 */
@Slf4j
@Component
public class ReportListener {

    @Autowired
    private CacheFeign cacheFeign;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //延时时间
    public final String[] TTL={"1000","3000","30000","60000","300000"};

    //监听MQ中的的push_sms_report_topic队列，接受回调对象
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void reportMessages(StandardReport report){

        //1.获取客户端id
        long clientID = report.getClientID();
        //2.根据客户端id远程调用cache服务，到redis中获取客户端对象
        Map<String,String> clientMap = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + clientID);
        //3.从客户端对象中湖区客户预留的服务器的ip地址和端口号
        String url = clientMap.get("receivestatusurl");
        //向回调对象中设置推送目标服务器的地址
        report.setReceiveStatusUrl(url);
        //设置当前推送的次数，当前第一次推送
        report.setSendCount(1);
        //4，获取客户端对象中，客户是否需要回调数据状态
        String isreturnstatus = clientMap.get("isreturnstatus");
        //5.判断客户如果需要回调数据，则发送回调数据
        if("1".equals(isreturnstatus)){
            //6.发送到回调数据后，判断客户返回的状态，客户是否接收到回调数据 1.返回 0不返回
            sendReport(report);
        }else{
            //7.如果客户不需要回调数据，记录日志，推送流程结束
            log.info("[接口模块-客户项目回调数据推送]，客户不需要回调数据，推送结束,StandardReport={}",report);
        }
    }

    //监听延时队列，获取延时推送消息
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayQueueListener(StandardReport report){
        //判断发送次数
        int count = report.getSendCount();
        if(count<=5){
            sendReport(report);
        }else{
            log.info("[消息模块-延时消息]，推送失败，大于5次，停止推送，流程结束！StandardReport={}",report);
        }
    }

    //发送http请求进行推送
    private void sendReport(StandardReport report){
        //1.封装请求头
        HttpHeaders header=new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_JSON);
        //2.将请求体和请求头封装成http请求对象
        HttpEntity httpEntity=new HttpEntity(report,header);
        //3.发送http请求并返回响应
        String str = null;
        try {
            str = restTemplate.postForObject(report.getReceiveStatusUrl(), httpEntity, String.class);
        } catch (RestClientException e) {
            log.info("[接口模块- 推送回调消息]，推送失败，客户方服务器不通，从新延时发送！StandardReport={}",report);
            sendMessage(report);
        }
        //4.判断回调消息客户的接收状态
        isSuccess(str,report);
    }

    //将消息发送到延时队列中，延时推送
    private void sendMessage(StandardReport report) {
        //发送的次数
        int count = report.getSendCount();
        if (count <= 5) {
            rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, "delay",report, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    //设置消息的延时时间
                    message.getMessageProperties().setExpiration(TTL[count]);
                    return message;
                }
            });
        }else{
            log.info("[消息模块-延时消息]，推送失败，大于5次，停止推送，流程结束！StandardReport={}",report);
        }
    }

    //判断推送状态是否发送成功,如果不成功继续推送，如果成功，流程结束
    private void isSuccess(String str,StandardReport report){
        if("SUCCESS".equalsIgnoreCase(str)){
            log.info("[]，推送成功，流程结束，StandardReport={}",report);
        }else{
            log.info("[]，推送失败，稍后延时，继续推送，StandardReport={}",report);
            sendMessage(report);
            //发送次数+1
            report.setSendCount( report.getSendCount()+1);
        }
    }
}
